<?php
/**
 * Строит HTML-страницу
 *
 * @since 30.10.2011
 * @author Akulov Denis <akulov.d.g@gmail.com>
 */
class K_Builder {

    /**
     * @var K_Container_OnlyRead
     */
    private $_objContainer = null;


    public function __construct(K_Container_OnlyRead $container) {
        $this->_objContainer = $container;
    }


    public function build () {
        // Пытаемся авторизовать пользователя по сессии

        /* @var $factoryModels K_MVC_Model_Factory */
        $factoryModels = $this->_objContainer->get('factory_models');
        /* @var $user M_ACL_User */
        $user = $factoryModels->factory('ACL_User');
        /* @var $gc K_GlobalContext */
        $gc = $this->_objContainer->get('global_context');

        $gc->set('AclUser', $user);

        if ($user->getLogin() == '@guest') {
            $this->athorization();
        }


        // Создадим путь к MVC/VC - узлу
        $mvcPath = new K_MVC_Path_Primary(
            new K_MVC_PathCorrector($this->_objContainer->get('CONFIG')),
            $this->_objContainer->get('SERVER')->get('REQUEST_URI')
        );

        // Вычислим путь к контроллеру
        $pathToController = $this->_objContainer->get('CONFIG')->getConfig('PROJECT_PATH');
        $pathToController .= '/controllers';
        $pathToController .= $mvcPath->isAjax() ? '/ajax' : '/primary';
        $pathToController .= '/'.$mvcPath->getController().EXT;

        // Проверим существование файла контроллера
        if (!is_file($pathToController)) {
            die ('page not found: not implamented (1)');
        }

        // Подключим файл с контроллером
        require_once $pathToController;

        // Вычислим имя класса контроллера
        $className = PREFIX_CONTROLLER.$mvcPath->getController();
        $className .= ($mvcPath->isAjax()) ? '_Ajax' : '';

        // Проверим существование класса контроллера
        if (!class_exists($className, false)) {
            die ('page not found: not implamented (2)');
        }

        // Создадим объект - контроллер
        /* @var $mvcNode K_MVC_Controller_PrimaryAbstract */
        $mvcNode = new $className ();

        // Требуем точное соответствие имени класса с учетом регистра
        if(get_class($mvcNode) != $className) {
            die ('page not found: not implamented (4)');
        }

        // Проверим наличие нужного метода в контроллере. Требуем точное совпадение.
        if(!in_array($mvcPath->getMethod(), get_class_methods($className))) {
            die ('page not found: not implamented (5)');
        }

        $mvcNode->_setContainer($this->_objContainer);

        $mvcNode->_setViewContainer(new K_MVC_View_Container(
            $this->_objContainer->get('CONFIG')
        ));

        // Если нет доступа
        if (!$this->isAllowedFunction($mvcPath)) {
            $mvcNode->_accessDeniedHandler($mvcPath->getMethod(), $mvcPath->getParams());
            return $mvcNode->_render();
        }

        // Вызов узла метода
        if ($this->_objContainer->get('POST')->isEmpty()) {
            call_user_func_array(
                array($mvcNode, $mvcPath->getMethod()),
                $mvcPath->getParams()
            );
        } else {
            call_user_func_array(
                array($mvcNode, $mvcPath->getMethod().'Submit'),
                $mvcPath->getParams()
            );
        }

        // Если контроллер - AJAX, то выходим
        if ($mvcPath->isAjax()) {
            // TODO возможно рендер узла
            return ;
        }

        // Создадим объект - каркас HTML-страницы
        $objCarcass = new K_Carcass(
            $mvcPath->getController(),
            $this->_objContainer->get('CONFIG')
        );

        // Получим список slave MVC/VC-узлов
        $arSlaveNodes = $objCarcass->getNodes();

        $arSlaveControllers = array();
        $arResult = array();

        // Собираем slave-контроллеры
        foreach ($arSlaveNodes as $pathToSlaveNode) {
            if ($pathToSlaveNode != K_Carcass::MAIN_REQUEST) {
                // Вычисляем MVC-путь для slave-контроллера
                $mvcSlavePath = null;
                $mvcSlavePath = new K_MVC_Path_Slave($pathToSlaveNode);

                // Вычисляем имя контроллера
                $slaveControllerName = '';
                $slaveControllerName = PREFIX_CONTROLLER.$mvcSlavePath->getController().'_Slave';

                // Eсли контроллер еще не создан, то создаем его
                if (empty($arSlaveControllers[$slaveControllerName])) {
                    // Вычисляем путь к slave-контроллеру
                    $pathToSlaveController = '';
                    $pathToSlaveController = $this->_objContainer->get('CONFIG')->getConfig('PROJECT_PATH');
                    $pathToSlaveController .= '/controllers/slave/'.$mvcSlavePath->getController().EXT;

                    // Подключаем файл с контроллером
                    require_once $pathToSlaveController;

                    // Создаем объект контроллера
                    $arSlaveControllers[$slaveControllerName] = new $slaveControllerName();

                    // Добавляем к контроллеру представление
                    $arSlaveControllers[$slaveControllerName]->_setViewContainer(new K_MVC_View_Container(
                        $this->_objContainer->get('CONFIG')
                    ));
                }

                // Получаем имя метода к которому идет запрос
                $slaveNodeMethod = $mvcSlavePath->getMethod();

                // Очищаем буфер View
                $arSlaveControllers[$slaveControllerName]->_cleanViewContainer();

                // Вызываем узел
                $arSlaveControllers[$slaveControllerName]->$slaveNodeMethod($mvcSlavePath->getParams());

                // Складываем результат
                $arResult[$pathToSlaveNode] = $arSlaveControllers[$slaveControllerName]->_render();
            } else {
                // Получаем результат от primary-узла
                $arResult[K_Carcass::MAIN_REQUEST] = $mvcNode->_render();
            }
        }

        // Формируем конечную HTML-страницу
        return $objCarcass->render($arResult);
    }


    private function athorization() {
        /* @var $objSession Container_OnlyRead_Interface */
        $objSession = $this->_objContainer->get('SESSION');

        if ($objSession->isExists('login') && $objSession->isExists('password')) {
            /* @var $factoryModels K_MVC_Model_Factory */
            $factoryModels = $this->_objContainer->get('factory_models');

            /* @var $athorizationData M_ACL_AthorizationData */
            $athorizationData = $factoryModels->factory('ACL_AthorizationData');

            $athorizationData->setLogin($objSession->get('login'));
            $athorizationData->setPassword($objSession->get('password'));

            /* @var $gc K_GlobalContext */
            $gc = $this->_objContainer->get('global_context');


            /* @var $user M_ACL_User */
            $user = $gc->get('AclUser');

            $user->athorization($athorizationData);
        }
    }


    private function isAllowedFunction (K_MVC_Path_Primary $objMvcPath) {

//         /* @var $objModelLoader K_MVC_Model_Loader */
//         $objModelLoader = $this->_objContainer->get('MODEL_LOADER');

        $factoryModels = $this->_objContainer->get('factory_models');

        /* @var $objAccess M_ACL_Access */
        $access = $factoryModels->factory('ACL_Access');

        return $access->isAllowed(
            $objMvcPath->getController(),
            $objMvcPath->getMethod(),
            $objMvcPath->getParams()
        );
    }

}